package cn.com.scitc.licenseplateback.controller;

import biz.source_code.base64Coder.Base64Coder;
import cn.com.scitc.licenseplateback.absExcetion.ParamInvalidException;
import cn.com.scitc.licenseplateback.dao.JUserTokenDao;
import cn.com.scitc.licenseplateback.dao.MembershipInformationDao;
import cn.com.scitc.licenseplateback.dao.MyJUserTokenDao;
import cn.com.scitc.licenseplateback.dateFormat.DateFormat;
import cn.com.scitc.licenseplateback.md5.MD5Util;
import cn.com.scitc.licenseplateback.model.JUserTokensEntity;
import cn.com.scitc.licenseplateback.model.MembershipInformationEntity;
import cn.com.scitc.licenseplateback.redis.RedisUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Random;

@RestController
public class Login {

    /**
     * 日志
     */
    private Log log = LogFactory.getLog(getClass());

    /**
     * 缓存库
     */
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 日期时间库
     */
    @Autowired
    private DateFormat dateFormat;

    /**
     * 会员信息 CRUD
     */
    @Autowired
    private MembershipInformationDao membershipInformationDao;

    /**
     * 密码双重加密库
     */
    @Autowired
    private MD5Util md5Util;

    /**
     * 添加记住密码的信息
     */
    @Autowired
    private JUserTokenDao jUserTokenDao;

    /**
     * 自定义的 dao，根据token(非主键)进行查询
     */
    @Autowired
    private MyJUserTokenDao myJUserTokenDao;

    /**
     * 调用公共方法
     */
    @Autowired
    private PublicFunction publicFunction;


    /**
     * 用户获取登录滑块验证码
     *
     * @return 当前时间戳+随机数
     */
    @PostMapping("/loginCode")
    private String loginCode() {
        String code = dateFormat.getCurrentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < 4; i++) {
            code += random.nextInt(10);
        }
        redisUtil.set(code, "true");
        redisUtil.expire(code, 60);
        return code;
    }


    /**
     * 用户登录
     *
     * @param loginInfo    用户登录信息
     * @param rememberPass 用户开启了记住密码开关，null 或 相关数据
     * @param request      获取用户的请求头，获取用户登录的设备
     * @return 失败 返回错误信息  成功 返回 token
     */
    @PostMapping("/login")
    private String login(String loginInfo, String rememberPass, HttpServletRequest request) {

        /**
         * 用户是否选择了记住密码，记住密码是规定时间为3天
         * 0. 判断用户是否已经记住密码了，却又没有选择重新登录，而是选择手动界面登录，但此时数据库中已有数据了
         *      为了不让数据重复添加，在 rememberPass 不为空之前进行判断
         * 1. 判断返回的 rememberPass 是否为空
         * 2. 将用户的信息存入数据库，否则不做任何处理
         */

        if (rememberPass != "") {
            JSONObject jsonObject = JSONObject.parseObject(rememberPass);

            JUserTokensEntity existsUserId = myJUserTokenDao.findByUserId(jsonObject.get("userid").toString());

            if (existsUserId == null) {
                int count = Integer.valueOf(String.valueOf(jUserTokenDao.count() + 1));
                JUserTokensEntity jUserTokensEntity = new JUserTokensEntity(
                        count,
                        jsonObject.get("userid").toString(),
                        jsonObject.get("token").toString(),
                        dateFormat.getCurrentDateTime(),
                        Integer.valueOf(jsonObject.get("expires").toString())
                );
                JUserTokensEntity save = jUserTokenDao.save(jUserTokensEntity);
            } else {
                existsUserId.setLogintime(dateFormat.getCurrentDateTime());
                existsUserId.setToken(jsonObject.get("token").toString());
                jUserTokenDao.save(existsUserId);
            }
        }


        /**
         * 用户登录验证分三步走
         * 1. 验证用户的验证码
         * 2. 验证用户的账号是否存在
         * 3. 验证用户的密码是否正确 -- 注意：数据库存储密码为加密后的密码，匹配前需将登录进入加密后比对
         * 4. 登录成功 -- 将用户登录信息写入缓存，并生成 TOKEN 返回给客户端
         */

        JSONObject jsonObject = JSONObject.parseObject(loginInfo);

        //1. 验证用户的验证码
        Object code = redisUtil.get(jsonObject.get("Code").toString());
        if (code == null) {
            redisUtil.del(jsonObject.get("Code").toString());
            return "系统验证失败";
        }

        //2. 验证用户的账号是否存在
        MembershipInformationEntity member = membershipInformationDao.findbyMember(jsonObject.get("Account").toString());
        if (member == null) {
            redisUtil.del(jsonObject.get("Code").toString());
            return "身份信息错误";
        }

        //3. 验证用户的密码是否正确
        String pass = md5Util.FINALPASS(jsonObject.get("Pass").toString(), member.getStal());
        if (!member.getPassword().toString().equals(pass)) {
            redisUtil.del(jsonObject.get("Code").toString());
            return "身份信息错误";
        }

        //4.登录成功 -- 将用户登录信息写入缓存，并生成 TOKEN 返回给客户端
        //TOKEN -> key:身份证号(md5加密)-姓名(base64编码)     value:{设备类型,登录时间}
        String tokenKey = publicFunction.saveTokenFactoryRedis(jsonObject.get("Account").toString(), member.getName(), request);
        redisUtil.del(jsonObject.get("Code").toString());//登录成功删除验证码

        String[] sendInfo = {tokenKey};
        return JSONObject.toJSONString(sendInfo);
    }


    /**
     * 手机号登录
     *
     * @param phoneNumber 手机号
     * @param captcha     短信验证码
     * @param request     请求头
     * @return token
     */
    @PostMapping("/phoneLogin")
    private String phoneLogin(String phoneNumber, String captcha, HttpServletRequest request) {

        String info = redisUtil.get(phoneNumber).toString();
        if (captcha.equals(info)) {
            MembershipInformationEntity byMemberPhoneNumber = membershipInformationDao.findByMemberPhoneNumber(phoneNumber);
            if (byMemberPhoneNumber != null) {
                redisUtil.del(phoneNumber);
                return publicFunction.saveTokenFactoryRedis(byMemberPhoneNumber.getIdNumber(), byMemberPhoneNumber.getName(), request);
            } else {
                return "该手机号未注册";
            }
        }
        return "验证码错误";
    }

    /**
     * 若用户开启了记住密码，且当前还未登录，就会触发该方法
     * 获取前端发送的 token 验证有效性，做出相应处理
     *
     * @param token
     * @return
     */
    @PostMapping("/checkAutoLoginInfo")
    private String checkAutoLoginInfo(String token, HttpServletRequest request, HttpServletResponse response) {

        /**
         * 实现用户的记住密码功能
         * 1. 获取用户上一次记住密码 登录成功后保存在客户端本地的 token
         * 2. 将 token 进行数据查询，若有则，进行有效期校验，若无，则直接返回登录
         * 3. 若有效期有效，则将userid 进行解密，获取用户对象，直接登录
         */

        //2. 将 token 进行数据查询，若有则，进行有效期校验，若无，则直接返回登录

        JUserTokensEntity byToken = myJUserTokenDao.findByToken(token);

        if (byToken != null) {

            Date date = dateFormat.formatDateTime(byToken.getLogintime().toString(), byToken.getExpires());
            boolean comparison = dateFormat.currentDateComparison(date);
            if (comparison) {
                //token 有效
                //获取 userid 并进行解码
                String userid = Base64Coder.decodeString(byToken.getUserId());
                MembershipInformationEntity membershipInformationEntity = membershipInformationDao.findbyMember(userid);
                //如找到记录则检测是否已过期，过期则提示登录，未过期则获取user_id从而得到user对象，如未匹配到记录则直接提示登录。
                //这样的处理好处就是，避免将用户个人信息写入到不安全的cookie中去，不必采用username+password进行验证的方式。
                String tokenKey =publicFunction.saveTokenFactoryRedis(userid, membershipInformationEntity.getName(), request);
                return JSONObject.toJSONString(tokenKey);
            } else {
                //token 无效
                int deleteInfo = myJUserTokenDao.deleteByToken(token);
                response.setStatus(400);
                return String.valueOf(deleteInfo);
            }
        }
        //返回400 参数错误
        throw new ParamInvalidException();
    }



}
